/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦]
 * 
 * https://zhiqim.org/project/zhiqim_framework/zhiqim_httpd.htm
 *
 * Zhiqim Httpd is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.httpd.context.config;

import java.io.File;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.jar.JarEntry;

import org.zhiqim.httpd.HttpRequest;
import org.zhiqim.httpd.context.annotation.AnAction;
import org.zhiqim.httpd.context.annotation.AnIntercept;
import org.zhiqim.httpd.context.annotation.AnInterceptNot;
import org.zhiqim.httpd.context.core.Action;
import org.zhiqim.httpd.context.extend.SwitchAction;
import org.zhiqim.kernel.logging.Log;
import org.zhiqim.kernel.logging.LogFactory;
import org.zhiqim.kernel.model.FilterHandler;
import org.zhiqim.kernel.util.Arrays;
import org.zhiqim.kernel.util.Classes;
import org.zhiqim.kernel.util.Files;
import org.zhiqim.kernel.util.Jars;
import org.zhiqim.kernel.util.Lists;

/**
 * Action类加载器，加载配置了@AnAction配置的数据
 * 1.要求类是在包内
 * 2.要求类实现了Action接口
 * 3.如果是SwitchAction子类检查方法上的@AnAction和@AnInterceptor
 * 4.否则只检查类上的@AnAction和@AnInterceptor
 * 
 * @version v1.0.0 @author zouzhigang 2016-7-16 新建与整理
 */
public class ZActionPackageLoader implements FilterHandler
{
    private static final Log log = LogFactory.getLog(ZActionPackageLoader.class);
    
    private ZActionPackage actionPackage;
    
    public ZActionPackageLoader(ZActionPackage wapper)
    {
        this.actionPackage = wapper;
    }
    
    @Override
    public boolean handle(Object obj) throws Exception
    {
        Object[] objs = (Object[])obj;
        String className = null;
        if (objs[0] instanceof File)
        {
            File classPath = (File)objs[0];
            File classFile = (File)objs[1];
            className = Files.getClassName(classPath, classFile);
        }
        else
        {
            JarEntry jarEntry = (JarEntry)objs[1];
            className = Jars.getClassName(jarEntry);
        }
        
        if (className == null || !className.startsWith(actionPackage.getActionPackage()))
            return true;
        
        Class<?> clazz = Classes.forName(className);
        if (!Classes.isImplement(clazz, Action.class))
        {
            log.error("类[%s]未实现Action接口", className);
            return false;
        }
        
        Action actioner = (Action)Classes.newInstance(clazz);
        if (actioner instanceof SwitchAction)
        {//支持方法中注解@AnAction
            AnIntercept classInterceptor = clazz.getAnnotation(AnIntercept.class);
            
            Method[] methods = clazz.getDeclaredMethods();
            for (Method method : methods)
            {
                AnAction anAction = method.getAnnotation(AnAction.class);
                if (anAction == null)
                    continue;
                
                Class<?>[] params = method.getParameterTypes();
                if (params.length != 1)
                {
                    log.error("类[%s]方法[%s]参数个数不正确", className, method.getName());
                    return false;
                }
                
                if (params[0] != HttpRequest.class)
                {
                    log.error("类[%s]方法[%s]参数不是[HttpRequest]", className, method.getName());
                    return false;
                }
                
                AnIntercept methodInterceptor = method.getAnnotation(AnIntercept.class);
                AnInterceptNot methodInterceptorNot = method.getAnnotation(AnInterceptNot.class);
                String interceptor = getInterceptor(classInterceptor, methodInterceptor, methodInterceptorNot);
                
                actionPackage.getConfig().setActionOnPath(anAction.path(), actioner);
                
                ZAction action = new ZAction();
                action.setName(anAction.name());
                action.setPath(anAction.path());
                action.setInterceptor(interceptor);
                action.setForward(anAction.forward());
                action.setRedirect(anAction.redirect());
                action.setView(anAction.view());
                action.setClazz(className);
                action.setMethod(method.getName());
                action.setSuccess(anAction.success());
                
                actionPackage.addActionOnPackage(action);
            }
        }
        else
        {//仅找类中注解@AnAction
            AnAction anAction = clazz.getAnnotation(AnAction.class);
            if (anAction == null)
                return true;
            
            AnIntercept anInterceptor = clazz.getAnnotation(AnIntercept.class);
            String interceptor = anInterceptor==null?"":Arrays.toFilterSameStr(anInterceptor.value());
            
            actionPackage.getConfig().setActionOnPath(anAction.path(), actioner);
            
            ZAction action = new ZAction();
            action.setName(anAction.name());
            action.setPath(anAction.path());
            action.setInterceptor(interceptor);
            action.setForward(anAction.forward());
            action.setRedirect(anAction.redirect());
            action.setView(anAction.view());
            action.setInclude(anAction.include());
            action.setClazz(className);
            action.setMethod(null);
            action.setSuccess(anAction.success());
            
            actionPackage.addActionOnPackage(action);
        }
        
        return true;
    }

    /**
     * 通过类拦截，方法拦截和方法拦截例外，获取拦截最后的字符串
     * 
     * @param classInterceptor      类拦截
     * @param methodInterceptor     方法拦截
     * @param methodInterceptorNot  方法拦截例外
     * @return
     */
    public static String getInterceptor(AnIntercept classInterceptor, AnIntercept methodInterceptor, AnInterceptNot methodInterceptorNot)
    {
        List<String> interceptorList = new ArrayList<>();
        if (classInterceptor != null)
        {
            String[] interceptors = classInterceptor.value();
            for (String interceptor : interceptors)
            {
                interceptorList.add(interceptor);
            }
        }
        
        if (methodInterceptor != null)
        {
            String[] interceptors = methodInterceptor.value();
            for (String interceptor : interceptors)
            {
                interceptorList.add(interceptor);
            }
        }
        
        if (methodInterceptorNot != null)
        {
            String[] interceptors = methodInterceptorNot.value();
            for (String interceptor : interceptors)
            {
                interceptorList.remove(interceptor);
            }
        }
        
        return Lists.toString(interceptorList, ",");
    }
}
